/*
 * @Author: Suo-Yuheng syh15399227325@163.com
 * @Date: 2025-09-10 22:31:36
 * @LastEditors: Suo-Yuheng syh15399227325@163.com
 * @LastEditTime: 2025-09-12 11:40:06
 * @FilePath: /0910/HttpServer.hpp
 * @Description: 修复MIME类型和路径问题
 */
#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <vector>
#include <sstream>
#include <map>
#include <cstring> // 新增，用于realpath

#include "Socket.hpp"
#include "log.hpp"
#include <algorithm>

static const int defaultport = 8888;

const std::string wwwroot = "./wwwroot";    // 网站根目录
const std::string homepage = "vsGame.html"; // 修改默认首页为游戏页面

const std::string sep = "\r\n";

// 完善MIME类型映射表，确保所有需要的类型都被正确定义
const std::map<std::string, std::string> mime_types = {
    {".html", "text/html; charset=utf-8"},
    {".htm", "text/html; charset=utf-8"},
    {".css", "text/css; charset=utf-8"},       // 确保CSS类型正确
    {".js", "text/javascript; charset=utf-8"}, // JS正确类型
    {".txt", "text/plain; charset=utf-8"},
    {".jpg", "image/jpeg"},
    {".jpeg", "image/jpeg"},
    {".png", "image/png"},
    {".gif", "image/gif"},
    {".svg", "image/svg+xml; charset=utf-8"},
    {".ttf", "font/ttf"},
    {".woff", "font/woff"},
    {".woff2", "font/woff2"},
    {".ico", "image/x-icon"},
    {".json", "application/json; charset=utf-8"}};

class HttpServer;

struct ThreadData
{
public:
    ThreadData(int fd, HttpServer *ts)
        : sockfd(fd), httpsvr(ts)
    {
    }

    int sockfd;
    HttpServer *httpsvr;
};

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        while (true)
        {
            ssize_t pos = req.find(sep);
            if (pos == std::string::npos)
                break;
            std::string temp = req.substr(0, pos);

            if (temp.empty())
                break;

            req_header.push_back(temp);

            req.erase(0, pos + sep.size());
        }

        req_text = req;
    }

    // 2. 完善Parse方法，确保file_path不会为空
    void Parse()
    {
        if (req_header.empty())
        {
            file_path = "";
            return;
        }

        std::stringstream s((req_header[0]));
        s >> method >> url >> http_version;

        // 关键修复：移除URL中的查询参数（?及后面的内容）
        size_t query_pos = url.find('?');
        if (query_pos != std::string::npos)
        {
            url = url.substr(0, query_pos); // 只保留?之前的路径部分
            std::cout << "移除查询参数后的URL: " << url << std::endl;
        }

        std::cout << "请求URL: " << url << std::endl;

        std::vector<std::string> possible_paths;
        possible_paths.push_back(wwwroot + url);
        possible_paths.push_back(wwwroot + url + ".html");
        possible_paths.push_back(wwwroot + "/test" + url);
        possible_paths.push_back(wwwroot + "/test" + url + ".html");

        if (url == "/" || url.empty())
        {
            possible_paths.clear();
            possible_paths.push_back(wwwroot + "/" + homepage);
            possible_paths.push_back(wwwroot + "/test/" + homepage);
            possible_paths.push_back(wwwroot + "/" + homepage + ".html");
            possible_paths.push_back(wwwroot + "/test/" + homepage + ".html");
        }

        // 遍历所有可能的路径
        file_path = "";
        for (const auto &path : possible_paths)
        {
            std::ifstream test(path);
            if (test.good())
            {
                file_path = path;
                break;
            }
        }

        // 如果所有路径都找不到，设置一个无效但非空的路径
        if (file_path.empty())
        {
            file_path = "invalid_file_path";
            std::cout << "文件未找到: " << url << std::endl;
        }

        std::cout << "最终文件路径: " << file_path << std::endl;
    }

    void DebugPrint()
    {
        for (auto &line : req_header)
        {
            std::cout << "--------------------------------------" << std::endl;
            std::cout << line << std::endl;
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;

        std::cout << req_text << std::endl;
    }

public:
    std::vector<std::string> req_header;
    std::string req_text;

    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {
    }

    bool Start()
    {
        // 打印当前工作目录（非常重要！）
        char cwd[1024];
        if (getcwd(cwd, sizeof(cwd)) != nullptr)
        {
            std::cout << "当前服务器运行目录: " << cwd << std::endl;
            std::cout << "wwwroot实际路径: " << cwd << "/" << wwwroot << std::endl;
        }

        listensock_.Socket();

        listensock_.Bind(port_);
        listensock_.Listen();
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if (sockfd < 0)
                continue;

            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd, this);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

    // 1. 修复MIME类型获取函数，添加空路径检查
    static std::string getMimeType(const std::string &file_path)
    {
        // 新增：检查文件路径是否为空
        if (file_path.empty())
        {
            return "application/octet-stream";
        }

        size_t dot_pos = file_path.find_last_of('.');
        if (dot_pos == std::string::npos || dot_pos == file_path.length() - 1)
        {
            return "application/octet-stream";
        }

        std::string ext = file_path.substr(dot_pos);
        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

        auto it = mime_types.find(ext);
        if (it != mime_types.end())
        {
            return it->second;
        }

        return "application/octet-stream";
    }

    static std::string ReadFileContent(const std::string &file_path)
    {
        std::ifstream in(file_path, std::ios::binary);
        if (!in.is_open())
            return "";

        in.seekg(0, std::ios_base::end);
        std::streamsize len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        content.resize(static_cast<size_t>(len));
        in.read(&content[0], len);

        in.close();
        return content;
    }

    // 调整CSP策略，允许eval并简化规则
    static std::string getCSPHeader()
    {
        return "default-src 'self'; "
               "style-src 'self' 'unsafe-inline'; "
               "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " // 明确允许eval
               "img-src 'self' data:; "
               "font-src 'self'; "
               "frame-ancestors 'none';";
    }

    // 3. 增强HandlerHttp函数的异常处理
    static void HandlerHttp(int sockfd, HttpServer *httpsvr)
    {
        try
        {
            char buffer[10240];
            ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n <= 0)
            {
                if (n < 0)
                    std::cerr << "接收数据失败: " << strerror(errno) << std::endl;
                close(sockfd);
                return;
            }

            buffer[n] = '\0';
            std::cout << "接收到请求: " << buffer << std::endl;

            HttpRequest req;
            req.Deserialize(buffer);
            req.Parse();
            req.DebugPrint();

            // 检查文件路径是否有效
            bool file_exists = !req.file_path.empty() && req.file_path != "invalid_file_path";
            std::string text;

            if (file_exists)
            {
                text = ReadFileContent(req.file_path);
                file_exists = !text.empty();
            }

            if (!file_exists)
            {
                std::cerr << "文件未找到: " << req.file_path << std::endl;
                text = "<html><body><h1>404 Not Found</h1><p>请求的资源不存在: " + req.url + "</p></body></html>";
            }

            std::string response_line = file_exists ? "HTTP/1.1 200 OK\r\n" : "HTTP/1.1 404 Not Found\r\n";

            std::string response_header;
            // 确保Content-Type包含charset=utf-8
            response_header += "Content-Type: " + getMimeType(req.file_path) + "\r\n";
            response_header += "Content-Length: " + std::to_string(text.size()) + "\r\n";
            response_header += "Connection: close\r\n";
            response_header += "X-Content-Type-Options: nosniff\r\n";

            // 确保添加CSP头（之前可能被注释掉了）
            response_header += "Content-Security-Policy: " + getCSPHeader() + "\r\n";

            // 修复缓存控制头
            std::string ext = req.file_path.substr(req.file_path.find_last_of('.'));
            if (ext == ".html" || ext == ".htm")
            {
                // HTML文件短期缓存
                response_header += "Cache-Control: public, max-age=180\r\n"; // 3分钟
            }
            else
            {
                // 静态资源长期缓存
                response_header += "Cache-Control: public, max-age=31536000, immutable\r\n";
            }

            std::string blank_line = "\r\n";
            std::string response = response_line + response_header + blank_line + text;

            ssize_t sent = send(sockfd, response.c_str(), response.size(), 0);
            if (sent < 0)
            {
                std::cerr << "发送响应失败: " << strerror(errno) << std::endl;
            }
            else
            {
                std::cout << "已发送 " << sent << " 字节给客户端" << std::endl;
            }

            close(sockfd);
        }
        catch (const std::out_of_range &e)
        {
            std::cerr << "字符串操作异常: " << e.what() << std::endl;
            close(sockfd);
        }
        catch (const std::exception &e)
        {
            std::cerr << "处理请求时发生异常: " << e.what() << std::endl;
            close(sockfd);
        }
        catch (...)
        {
            std::cerr << "发生未知异常" << std::endl;
            close(sockfd);
        }
    }

    static void *ThreadRun(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);

        pthread_detach(pthread_self());

        HandlerHttp(td->sockfd, td->httpsvr);

        delete td;
        return nullptr;
    }

    ~HttpServer()
    {
    }

private:
    Sock listensock_;
    uint16_t port_;
};
